home *** CD-ROM | disk | FTP | other *** search
/ Software Vault: The Gold Collection / Software Vault - The Gold Collection (American Databankers) (1993).ISO / cdr48 / cgterm10.zip / PIBASYN1.MOD < prev    next >
Text File  |  1993-04-01  |  59KB  |  1,031 lines

  1. (*----------------------------------------------------------------------*)
  2. (*         PIBASYNC.PAS   --- Asynchronous I/O for Turbo Pascal         *)
  3. (*----------------------------------------------------------------------*)
  4. (*                                                                      *)
  5. (*  Author:  (c) 1985, 1986 by Philip R. Burns                          *)
  6. (*                                                                      *)
  7. (*  Version: 1.0   (January, 1985)                                      *)
  8. (*           2.0   (June, 1985)                                         *)
  9. (*           2.1   (July, 1985)                                         *)
  10. (*           3.0   (October, 1985)                                      *)
  11. (*           3.1   (October, 1985)                                      *)
  12. (*           3.2   (November, 1985)                                     *)
  13. (*           4.0   (October, 1986)                                      *)
  14. (*                                                                      *)
  15. (*  Systems: For MSDOS/PC DOS on IBM PCs and close compatibles only.    *)
  16. (*                                                                      *)
  17. (*  History: Some of these routines are based upon ones written by:     *)
  18. (*                                                                      *)
  19. (*              Alan Bishop                                             *)
  20. (*              C. J. Dunford                                           *)
  21. (*              Michael Quinlan                                         *)
  22. (*              Gene Harris                                             *)
  23. (*                                                                      *)
  24. (*           I have cleaned up these other authors' code, fixed some    *)
  25. (*           bugs, and added many new features.                         *)
  26. (*                                                                      *)
  27. (*           In particular, starting with v4.0 of PibTerm, both input   *)
  28. (*           and output to the serial port is buffered and interrupt-   *)
  29. (*           driven.  Also, XON/XOFF support has been moved to the      *)
  30. (*           serial port interrupt handler, which results in fewer      *)
  31. (*           overrun problems.                                          *)
  32. (*                                                                      *)
  33. (*           Suggestions for improvements or corrections are welcome.   *)
  34. (*                                                                      *)
  35. (*           If you use this code in your own programs, please be nice  *)
  36. (*           and give proper credit.                                    *)
  37. (*                                                                      *)
  38. (*----------------------------------------------------------------------*)
  39. (*                                                                      *)
  40. (*  Routines:                                                           *)
  41. (*                                                                      *)
  42. (*     BIOS_RS232_Init        ---    Use BIOS to initialize port        *)
  43. (*     DOS_Set_Intrpt         ---    Set interrupt vector using DOS     *)
  44. (*     DOS_Get_Intrpt         ---    Get interrupt vector using DOS     *)
  45. (*     Async_Isr              ---    Com port interrupt service routine *)
  46. (*     Async_Init             ---    Performs initialization.           *)
  47. (*     Async_Clear_Errors     ---    Clear pending serial port errors   *)
  48. (*     Async_Reset_Port       ---    Resets UART parameters for port    *)
  49. (*     Async_Open             ---    Sets up COM port                   *)
  50. (*     Async_Close            ---    Closes down COM port               *)
  51. (*     Async_Carrier_Detect   ---    Checks for modem carrier detect    *)
  52. (*     Async_Carrier_Drop     ---    Checks for modem carrier drop      *)
  53. (*     Async_Buffer_Check     ---    Checks if character in COM buffer  *)
  54. (*     Async_Term_Ready       ---    Toggles terminal ready status      *)
  55. (*     Async_Receive          ---    Reads character from COM buffer    *)
  56. (*     Async_Receive_With_Timeout                                       *)
  57. (*                            ---    Receives char. with timeout check  *)
  58. (*     Async_Ring_Detect      ---    If ringing detected                *)
  59. (*     Async_Send             ---    Transmits char over COM port       *)
  60. (*     Async_Send_String      ---    Sends string over COM port         *)
  61. (*     Async_Send_String_With_Delays                                    *)
  62. (*                            ---    Sends string with timed delays     *)
  63. (*     Async_Send_Break       ---    Sends break (attention) signal     *)
  64. (*     Async_Percentage_Used  ---    Returns percentage com buffer used *)
  65. (*     Async_Purge_Buffer     ---    Purges receive buffer              *)
  66. (*     Async_Release_Buffers  ---    Free memory for serial port queues *)
  67. (*     Async_Setup_Port       ---    Define port base, IRQ, RS232 addr  *)
  68. (*     Async_Stuff            ---    Insert char into receive buffer    *)
  69. (*                                                                      *)
  70. (*----------------------------------------------------------------------*)
  71. (*                                                                      *)
  72. (*      PIBASYNC.PAS was split into PIBASYN1.PAS and PIBASYN2.PAS at    *)
  73. (*      version 3.2 of PibTerm, and into PIBASYN1, PIBASYN2, and        *)
  74. (*      PIBASYN3 for v4.0 of PibTerm.                                   *)
  75. (*                                                                      *)
  76. (*----------------------------------------------------------------------*)
  77.  
  78. (*----------------------------------------------------------------------*)
  79. (*                BIOS_RS232_Init --- Initialize UART                   *)
  80. (*----------------------------------------------------------------------*)
  81.  
  82. PROCEDURE BIOS_RS232_Init( ComPort, ComParm : INTEGER );
  83.  
  84. (*----------------------------------------------------------------------*)
  85. (*                                                                      *)
  86. (*     Procedure:  BIOS_RS232_Init                                      *)
  87. (*                                                                      *)
  88. (*     Purpose:    Issues interrupt $14 to initialize the UART          *)
  89. (*                                                                      *)
  90. (*     Calling Sequence:                                                *)
  91. (*                                                                      *)
  92. (*        BIOS_RS232_Init( ComPort, ComParm : INTEGER );                *)
  93. (*                                                                      *)
  94. (*           ComPort  --- Communications Port Number (0 thru 3)         *)
  95. (*           ComParm  --- Communications Parameter Word                 *)
  96. (*                                                                      *)
  97. (*      Calls:   INTR   (to perform BIOS interrupt $14)                 *)
  98. (*                                                                      *)
  99. (*----------------------------------------------------------------------*)
  100.  
  101. VAR
  102.    Regs: RegPack;
  103.    Save: INTEGER;
  104.  
  105. BEGIN   (* BIOS_RS232_Init *)
  106.                                    (* Set RS 232 base. *)
  107.  
  108.    Save               := MEM[$0:RS232_Base];
  109.    MEM[$0:RS232_Base] := Async_RS232;
  110.  
  111.                                    (* Initialize port    *)
  112.    WITH Regs DO
  113.       BEGIN
  114.          Ax := ComParm AND $00FF;  (* AH=0; AL=ComParm   *)
  115.          Dx := ComPort;            (* Port number to use *)
  116.          INTR($14, Regs);
  117.       END;
  118.                                    (* Set RS 232 base back *)
  119.    MEM[$0:RS232_Base] := Save;
  120.  
  121. END    (* BIOS_RS232_Init *);
  122.  
  123. (*----------------------------------------------------------------------*)
  124. (*             DOS_Set_Intrpt --- Call DOS to set interrupt vector      *)
  125. (*----------------------------------------------------------------------*)
  126.  
  127. PROCEDURE DOS_Set_Intrpt( V, S, O : INTEGER );
  128.  
  129. (*----------------------------------------------------------------------*)
  130. (*                                                                      *)
  131. (*     Procedure:  DOS_Set_Intrpt                                       *)
  132. (*                                                                      *)
  133. (*     Purpose:    Calls DOS to set interrupt vector                    *)
  134. (*                                                                      *)
  135. (*     Calling Sequence:                                                *)
  136. (*                                                                      *)
  137. (*        DOS_Set_Intrpt( V, S, O : INTEGER );                          *)
  138. (*                                                                      *)
  139. (*           V --- interrupt vector number to set                       *)
  140. (*           S --- segment address of interrupt routine                 *)
  141. (*           O --- offset address of interrupt routine                  *)
  142. (*                                                                      *)
  143. (*      Calls:   MSDOS   (to set interrupt)                             *)
  144. (*                                                                      *)
  145. (*----------------------------------------------------------------------*)
  146.  
  147. VAR
  148.    Regs : Regpack;
  149.  
  150. BEGIN   (* DOS_Set_Intrpt *)
  151.  
  152.    WITH Regs DO
  153.       BEGIN
  154.          Ax := $2500 + ( V AND $00FF );
  155.          Ds := S;
  156.          Dx := O;
  157.          Es := 0;
  158.          MsDos( Regs );
  159.       END;
  160.  
  161. END    (* DOS_Set_Intrpt *);
  162.  
  163. (*----------------------------------------------------------------------*)
  164. (*             DOS_Get_Intrpt --- Call DOS to get interrupt vector      *)
  165. (*----------------------------------------------------------------------*)
  166.  
  167. PROCEDURE DOS_Get_Intrpt( V: INTEGER; VAR S: INTEGER; VAR O : INTEGER );
  168.  
  169. (*----------------------------------------------------------------------*)
  170. (*                                                                      *)
  171. (*     Procedure:  DOS_Get_Intrpt                                       *)
  172. (*                                                                      *)
  173. (*     Purpose:    Calls DOS to get interrupt vector                    *)
  174. (*                                                                      *)
  175. (*     Calling Sequence:                                                *)
  176. (*                                                                      *)
  177. (*        DOS_Get_Intrpt( V, S, O : INTEGER );                          *)
  178. (*                                                                      *)
  179. (*           V --- interrupt vector number to get                       *)
  180. (*           S --- segment address of interrupt routine                 *)
  181. (*           O --- offset address of interrupt routine                  *)
  182. (*                                                                      *)
  183. (*      Calls:   MSDOS   (to get interrupt)                             *)
  184. (*                                                                      *)
  185. (*----------------------------------------------------------------------*)
  186.  
  187. VAR
  188.    Regs : Regpack;
  189.  
  190. BEGIN   (* DOS_Get_Intrpt *)
  191.  
  192.    Regs.Ax := $3500 + ( V AND $00FF );
  193.  
  194.    MsDos( Regs );
  195.  
  196.    S := Regs.Es;
  197.    O := Regs.Bx;
  198.  
  199. END    (* DOS_Get_Intrpt *);
  200.  
  201. (*----------------------------------------------------------------------*)
  202. (*               Async_Isr --- Interrupt Service Routine                *)
  203. (*----------------------------------------------------------------------*)
  204.  
  205. PROCEDURE Async_Isr;
  206.  
  207. (*----------------------------------------------------------------------*)
  208. (*                                                                      *)
  209. (*     Procedure:  Async_Isr                                            *)
  210. (*                                                                      *)
  211. (*     Purpose:    Invoked when serial port interrupt occurs.           *)
  212. (*                                                                      *)
  213. (*     Calling Sequence:                                                *)
  214. (*                                                                      *)
  215. (*        Async_Isr;                                                    *)
  216. (*                                                                      *)
  217. (*           --- Called asynchronously only!!!!!!                       *)
  218. (*                                                                      *)
  219. (*----------------------------------------------------------------------*)
  220.  
  221. BEGIN   (* Async_Isr *)
  222.  
  223. INLINE(
  224.   $FB                                {         STI                                ;Allow interrupts}
  225.                                      {;}
  226.   /$50                               {         PUSH    AX                         ;Save registers}
  227.   /$53                               {         PUSH    BX}
  228.   /$51                               {         PUSH    CX}
  229.   /$52                               {         PUSH    DX}
  230.   /$1E                               {         PUSH    DS}
  231.   /$56                               {         PUSH    SI}
  232.   /$06                               {         PUSH    ES}
  233.   /$57                               {         PUSH    DI}
  234.                                      {;}
  235.                                      {;  Get data segment for addressing global variables}
  236.                                      {;}
  237.   /$2E/$8E/$1E/>ASYNC_DSEG_SAVE      {    CS:  MOV     DS,[>Async_DSeg_Save]}
  238.                                      {;}
  239.                                      {;  Begin major polling loop over pending interrupts.}
  240.                                      {;}
  241.                                      {;  The polling loop is needed because the 8259 cannot handle another 8250}
  242.                                      {;  interrupt while we service this interrupt.  We keep polling here as long}
  243.                                      {;  as an interrupt is received.}
  244.                                      {;}
  245.   /$8B/$16/>ASYNC_UART_IIR           {Poll:    MOV     DX,[>Async_Uart_IIR]       ;Get Interrupt ident register}
  246.   /$EC                               {         IN      AL,DX                      ;Pick up interrupt type}
  247.                                      {;}
  248.   /$A8/$01                           {         TEST    AL,1                       ;See if any interrupt signalled.}
  249.   /$74/$03                           {         JZ      Polla                      ;Yes --- continue}
  250.   /$E9/$7F/$01                       {         JMP     NEAR Back                  ;No  ---  return to invoker}
  251.                                      {;}
  252.                                      {;  Determine type of interrupt.}
  253.                                      {;  Possibilities:}
  254.                                      {;}
  255.                                      {;     0 = Modem status changed}
  256.                                      {;     2 = Transmit hold register empty (write char)}
  257.                                      {;     4 = Character received from port}
  258.                                      {;     6 = Line status changed}
  259.                                      {;}
  260.   /$24/$06                           {Polla:   AND     AL,6                       ;Strip unwanted bits from interrupt type}
  261.   /$3C/$04                           {         CMP     AL,4                       ;Check if interrupt >= 4}
  262.   /$74/$03                           {         JE      Pollb                      ;}
  263.   /$E9/$A1/$00                       {         JMP     NEAR Int2}
  264.                                      {;}
  265.                                      {;  Write interrupts must be turned on if a higher-priority interrupt}
  266.                                      {;  has been received, else the characters may not be sent (and a lockup}
  267.                                      {;  may occur).}
  268.                                      {;}
  269.   /$50                               {Pollb:   PUSH    AX                         ;Save interrupt type}
  270.   /$E8/$65/$01                       {         CALL    EnabWI                     ;Enable write interrupts}
  271.   /$58                               {         POP     AX                         ;Restore interrupt type}
  272.                                      {;}
  273.                                      {;  --- Received a character ----}
  274.                                      {;}
  275.   /$3C/$04                           {Int4:    CMP     AL,4                       ;Check for received char interrupt}
  276.   /$74/$03                           {         JE      Int4a                      ;Yes -- process it.}
  277.   /$E9/$95/$00                       {         JMP     NEAR Int2                  ;No -- skip.}
  278.                                      {;}
  279.                                      {;  Read the character from the serial port.}
  280.                                      {;}
  281.   /$8B/$16/>ASYNC_BASE               {Int4a:   MOV     DX,[>Async_Base]           ;Read character from port}
  282.   /$EC                               {         IN      AL,DX}
  283.                                      {;}
  284.                                      {;  Check if XON/XOFF honored.  If so, check if incoming character is}
  285.                                      {;  an XON or an XOFF.}
  286.                                      {;}
  287.   /$F6/$06/>ASYNC_DO_XONXOFF/$01     {        TEST    BYTE [<Async_Do_XonXoff],1 ;See if we honor XON/XOFF}
  288.   /$74/$25                           {         JZ      Int4d                      ;No -- skip XON/XOFF checks}
  289.                                      {;}
  290.   /$3C/<XON                          {         CMP     AL,<XON                    ;See if XON found}
  291.   /$74/$11                           {         JE      Int4b                      ;Skip if XON found}
  292.   /$3C/<XOFF                         {         CMP     AL,<XOFF                   ;See if XOFF found}
  293.   /$75/$1D                           {         JNE     Int4d                      ;Skip if XOFF not found}
  294.                                      {;}
  295.                                      {;  XOFF received -- set flag indicating sending of chars isn't possible}
  296.                                      {;}
  297.   /$C6/$06/>ASYNC_XOFF_RECEIVED/$01  {         MOV     BYTE [<Async_XOFF_Received],1    ;Turn on received XOFF flag}
  298.   /$C6/$06/>ASYNC_XOFF_REC_DISPLAY/$01{        MOV     BYTE [<Async_XOFF_Rec_Display],1 ;Turn on display flag}
  299.   /$E9/$BE/$FF                       {         JMP     NEAR Poll}
  300.                                      {;}
  301.                                      {;  XON received -- allow more characters to be sent.}
  302.                                      {;}
  303.   /$C6/$06/>ASYNC_XOFF_RECEIVED/$00  {Int4b:   MOV     BYTE [<Async_XOFF_Received],0   ;Turn off received XOFF flag}
  304.   /$C6/$06/>ASYNC_XON_REC_DISPLAY/$01{         MOV     BYTE [<Async_XON_Rec_Display],1 ;Turn on display flag}
  305.                                      {;}
  306.   /$E8/$2F/$01                       {         CALL    EnabWI                     ;Enable write interrupts}
  307.   /$E9/$61/$00                       {         JMP     NEAR Int4z}
  308.                                      {;}
  309.                                      {;  Not XON/XOFF -- handle other character.}
  310.                                      {;}
  311.   /$F6/$06/>ASYNC_LINE_STATUS/$02{Int4d:       TEST    BYTE [>Async_Line_Status],2 ;Check for buffer overrun}
  312.   /$75/$5A                           {         JNZ     Int4z                      ;Yes --- don't store anything}
  313.                                      {;}
  314.   /$8B/$1E/>ASYNC_BUFFER_HEAD        {         MOV     BX,[>Async_Buffer_Head]    ;Current position in input buffer}
  315.   /$C4/$3E/>ASYNC_BUFFER_PTR         {         LES     DI,[>Async_Buffer_Ptr]     ;Pick up buffer address}
  316.   /$01/$DF                           {         ADD     DI,BX                      ;Update position}
  317.   /$26/$88/$05                       {     ES: MOV     [DI],AL                    ;Store received character in buffer}
  318.   /$FF/$06/>ASYNC_BUFFER_USED        {         INC     WORD [>Async_Buffer_Used]  ;Increment count of chars in buffer}
  319.                                      {;}
  320.   /$A1/>ASYNC_BUFFER_USED            {         MOV     AX,[>Async_Buffer_Used]    ;Pick up buffer usage count}
  321.   /$3B/$06/>ASYNC_MAXBUFFERUSED      {         CMP     AX,[>Async_MaxBufferUsed]  ;See if greater usage than ever before}
  322.   /$7E/$03                           {         JLE     Int4f                      ;Skip if not}
  323.   /$A3/>ASYNC_MAXBUFFERUSED          {         MOV     [>Async_MaxBufferUsed],AX  ;This is greatest use thus far}
  324.                                      {;}
  325.   /$43                               {Int4f:   INC     BX                         ;Increment buffer pointer}
  326.   /$3B/$1E/>ASYNC_BUFFER_SIZE        {         CMP     BX,[>Async_Buffer_Size]    ;Check if past end of buffer}
  327.   /$7E/$02                           {         JLE     Int4h}
  328.   /$31/$DB                           {         XOR     BX,BX                      ;If so, wrap around to front}
  329.                                      {;}
  330.   /$39/$1E/>ASYNC_BUFFER_TAIL        {Int4h:   CMP     WORD [>Async_Buffer_Tail],BX ;Check for overflow}
  331.   /$74/$29                           {         JE      Int4s                      ;Jump if head ran into tail}
  332.                                      {;}
  333.   /$89/$1E/>ASYNC_BUFFER_HEAD        {         MOV     [>Async_Buffer_Head],BX    ;Update head pointer}
  334.                                      {;}
  335.                                      {;  If XON/XOFF available, and buffer getting full, set up to send}
  336.                                      {;  XOFF to remote system.}
  337.                                      {;}
  338.                                      {;  This happens in two possible stages:}
  339.                                      {;}
  340.                                      {;     (1)  An XOFF is sent right when the buffer becomes 'Async_Buffer_High'}
  341.                                      {;          characters full.}
  342.                                      {;}
  343.                                      {;     (2)  A second XOFF is sent right when the buffer becomes}
  344.                                      {;          'Async_Buffer_High_2' characters full;  this case is likely the}
  345.                                      {;          result of the remote not having seen our XOFF because it was}
  346.                                      {;          lost in transmission.}
  347.                                      {;}
  348.   /$F6/$06/>ASYNC_DO_XONXOFF/$01     {         TEST    BYTE [<Async_Do_XonXoff],1 ;See if we honor XON/XOFF}
  349.   /$74/$23                           {         JZ      Int4z                      ;No -- skip XON/XOFF checks}
  350.                                      {;}
  351.                                      {;  Check against first high-water mark.}
  352.                                      {;}
  353.   /$3B/$06/>ASYNC_BUFFER_HIGH        {         CMP     AX,[>Async_Buffer_High]    ;AX still has Async_Buffer_Used}
  354.   /$7C/$1D                           {         JL      Int4z                      ;Not very full, so keep going.}
  355.                                      {;}
  356.                                      {;  Check if we've already sent XOFF.}
  357.                                      {;}
  358.   /$F6/$06/>ASYNC_XOFF_SENT/$01      {         TEST    BYTE [<Async_XOFF_Sent],1  ;Remember if we sent XOFF or not}
  359.   /$74/$06                           {         JZ      Int4j                      ;No -- go send it now.}
  360.                                      {;}
  361.                                      {;  Check against second high-water mark.}
  362.                                      {;  If we are right at it, send an XOFF regardless of whether we've}
  363.                                      {;  already sent one or not.  (Perhaps the first got lost.)}
  364.                                      {;}
  365.   /$3B/$06/>ASYNC_BUFFER_HIGH_2      {         CMP     AX,[>Async_Buffer_High_2]}
  366.   /$75/$10                           {         JNE     Int4z                      ;Not at 2nd mark -- skip}
  367.                                      {;}
  368.   /$C6/$06/>ASYNC_SEND_XOFF/$01      {Int4j:   MOV     BYTE [<Async_Send_XOFF],1  ;Indicate we need to send XOFF}
  369.   /$E8/$D3/$00                       {         CALL    EnabWI                     ;Ensure write interrupts enabled}
  370.   /$E9/$52/$FF                       {         JMP     NEAR Poll                  ;}
  371.                                      {;}
  372.                                      {;  If we come here, then the input buffer has overflowed.}
  373.                                      {;  Characters will be thrown away until the buffer empties at least one slot.}
  374.                                      {;}
  375.   /$80/$0E/>ASYNC_LINE_STATUS/$02    {Int4s:   OR      BYTE PTR [>Async_Line_Status],2 ;Flag overrun}
  376.                                      {;}
  377.   /$E9/$4A/$FF                       {Int4z:   JMP     NEAR Poll}
  378.                                      {;}
  379.                                      {;  --- Write a character ---}
  380.                                      {;}
  381.   /$3C/$02                           {Int2:    CMP     AL,2                       ;Check for THRE interrupt}
  382.   /$74/$03                           {         JE      Int2a                      ;Yes -- process it.}
  383.   /$E9/$97/$00                       {         JMP     NEAR Int6                  ;No -- skip.}
  384.                                      {;}
  385.                                      {;  Check first if we need to send an XOFF to remote system.}
  386.                                      {;}
  387.   /$F6/$06/>ASYNC_SEND_XOFF/$01      {Int2a:   TEST    BYTE [<Async_Send_Xoff],1  ;See if we are sending XOFF}
  388.   /$74/$34                           {         JZ      Int2d                      ;No -- skip it}
  389.                                      {;}
  390.                                      {;  Yes, we are to send XOFF to remote.}
  391.                                      {;}
  392.                                      {;  First, check DSR and CTS as requested.}
  393.                                      {;  If those status lines aren't ready, turn off write interrupts and}
  394.                                      {;  try later, after a line status change.}
  395.                                      {;}
  396.   /$F6/$06/>ASYNC_DO_DSR/$01         {         TEST    BYTE [<Async_Do_DSR],1     ;See if DSR checking required}
  397.   /$74/$09                           {         JZ      Int2b                      ;No -- skip it}
  398.                                      {;}
  399.   /$8B/$16/>ASYNC_UART_MSR           {         MOV     DX,[>Async_Uart_MSR]       ;Get modem status register}
  400.   /$EC                               {         IN      AL,DX}
  401.   /$A8/<ASYNC_DSR                    {         TEST    AL,<Async_DSR              ;Check for Data Set Ready}
  402.   /$74/$2E                           {         JZ      Int2e                      ;If not DSR, turn off write interrupts}
  403.                                      {;}
  404.   /$F6/$06/>ASYNC_DO_CTS/$01         {Int2b:   TEST    BYTE [<Async_Do_CTS],1     ;See if CTS checking required}
  405.   /$74/$09                           {         JZ      Int2c                      ;No -- skip it}
  406.                                      {;}
  407.   /$8B/$16/>ASYNC_UART_MSR           {         MOV     DX,[>Async_Uart_MSR]       ;Get modem status register}
  408.   /$EC                               {         IN      AL,DX}
  409.   /$A8/<ASYNC_CTS                    {         TEST    AL,<Async_CTS              ;Check for Clear To Send}
  410.   /$74/$1E                           {         JZ      Int2e                      ;If not CTS, turn off write ints}
  411.                                      {;}
  412.                                      {;  All status lines look OK.}
  413.                                      {;  Send the XOFF.}
  414.                                      {;}
  415.   /$B0/<XOFF                         {Int2c:   MOV     AL,<XOFF                   ;Get XOFF Character}
  416.   /$8B/$16/>ASYNC_BASE               {         MOV     DX,[>Async_Base]           ;Get transmit hold register address}
  417.   /$EE                               {         OUT     DX,AL                      ;Output the XOFF}
  418.   /$C6/$06/>ASYNC_SEND_XOFF/$00      {         MOV     BYTE [<Async_Send_XOFF],0  ;Turn off send XOFF flag}
  419.   /$C6/$06/>ASYNC_XOFF_SENT/$01      {         MOV     BYTE [<Async_XOFF_Sent],1  ;Turn on sent XOFF flag}
  420.   /$E9/$08/$FF                       {         JMP     NEAR Poll                  ;Return}
  421.                                      {;}
  422.                                      {;  Not sending XOFF -- see if any character in buffer to be sent.}
  423.                                      {;}
  424.   /$8B/$1E/>ASYNC_OBUFFER_TAIL       {Int2d:   MOV     BX,[>Async_OBuffer_Tail]   ;Pick up output buffer pointers}
  425.   /$3B/$1E/>ASYNC_OBUFFER_HEAD       {         CMP     BX,[>Async_OBuffer_Head]}
  426.   /$75/$0B                           {         JNE     Int2m                      ;Skip if not equal --> something to send}
  427.                                      {;}
  428.                                      {;  If nothing to send, turn off write interrupts to avoid unnecessary}
  429.                                      {;  time spent handling useless THRE interrupts.}
  430.                                      {;}
  431.   /$8B/$16/>ASYNC_UART_IER           {Int2e:   MOV     DX,[>Async_Uart_IER]       ;If nothing -- or can't -- send ...}
  432.   /$EC                               {         IN      AL,DX                      ;}
  433.   /$24/$FD                           {         AND     AL,$FD                     ;}
  434.   /$EE                               {         OUT     DX,AL                      ;... disable write interrupts}
  435.   /$E9/$F3/$FE                       {         JMP     NEAR Poll                  ;}
  436.                                      {;}
  437.                                      {;  If something to send, ensure that remote system didn't send us XOFF.}
  438.                                      {;  If it did, we can't send anything, so turn off write interrupts and}
  439.                                      {;  wait for later (after an XON has been received).}
  440.                                      {;}
  441.   /$F6/$06/>ASYNC_XOFF_RECEIVED/$01  {Int2m:   TEST    BYTE [<Async_XOFF_Received],1 ;See if we received XOFF}
  442.   /$75/$EE                           {         JNZ     Int2e                      ;Yes -- can't send anything now}
  443.                                      {;}
  444.                                      {;  If we can send character, check DSR and CTS as requested.}
  445.                                      {;  If those status lines aren't ready, turn off write interrupts and}
  446.                                      {;  try later, after a line status change.}
  447.                                      {;}
  448.   /$8B/$16/>ASYNC_UART_MSR           {         MOV     DX,[>Async_Uart_MSR]       ;Otherwise get modem status}
  449.   /$EC                               {         IN      AL,DX}
  450.   /$A2/>ASYNC_MODEM_STATUS           {         MOV     [>Async_Modem_Status],AL   ;and save modem status for later}
  451.                                      {;}
  452.   /$F6/$06/>ASYNC_DO_DSR/$01         {         TEST    BYTE [<Async_Do_DSR],1     ;See if DSR checking required}
  453.   /$74/$04                           {         JZ      Int2n                      ;No -- skip it}
  454.                                      {;}
  455.   /$A8/<ASYNC_DSR                    {         TEST    AL,<Async_DSR              ;Check for Data Set Ready}
  456.   /$74/$DB                           {         JZ      Int2e                      ;If not DSR, turn off write ints}
  457.                                      {;}
  458.   /$F6/$06/>ASYNC_DO_CTS/$01         {Int2n:   TEST    BYTE [<Async_Do_CTS],1     ;See if CTS checking required}
  459.   /$74/$04                           {         JZ      Int2o                      ;No -- skip it}
  460.                                      {;}
  461.   /$A8/<ASYNC_CTS                    {         TEST    AL,<Async_CTS              ;Check for Clear To Send}
  462.   /$74/$D0                           {         JZ      Int2e                      ;If not CTS, turn off write ints}
  463.                                      {;}
  464.                                      {;  Everything looks OK for sending, so send the character.}
  465.                                      {;}
  466.   /$C4/$3E/>ASYNC_OBUFFER_PTR        {Int2o:   LES     DI,[>Async_OBuffer_Ptr]    ;Get output buffer pointer}
  467.   /$01/$DF                           {         ADD     DI,BX                      ;Position to character to output}
  468.   /$26/$8A/$05                       {     ES: MOV     AL,[DI]                    ;Get character to output}
  469.   /$8B/$16/>ASYNC_BASE               {         MOV     DX,[>Async_Base]           ;Get transmit hold register address}
  470.   /$EE                               {         OUT     DX,AL                      ;Output the character}
  471.                                      {;}
  472.   /$FF/$0E/>ASYNC_OBUFFER_USED       {         DEC     WORD [>Async_OBuffer_Used] ;Decrement count of chars in buffer}
  473.   /$43                               {         INC     BX                         ;Increment tail pointer}
  474.   /$3B/$1E/>ASYNC_OBUFFER_SIZE       {         CMP     BX,[>Async_OBuffer_Size]   ;See if past end of buffer}
  475.   /$7E/$02                           {         JLE     Int2z}
  476.   /$31/$DB                           {         XOR     BX,BX                      ;If so, wrap to front}
  477.                                      {;}
  478.   /$89/$1E/>ASYNC_OBUFFER_TAIL       {Int2z:   MOV     [>Async_OBuffer_Tail],BX   ;Store updated buffer tail}
  479.   /$E9/$AC/$FE                       {         JMP     NEAR Poll}
  480.                                      {;}
  481.                                      {;  --- Line status change ---}
  482.                                      {;}
  483.   /$3C/$06                           {Int6:    CMP     AL,6                       ;Check for line status interrupt}
  484.   /$75/$11                           {         JNE     Int0                       ;No -- skip.}
  485.                                      {;}
  486.   /$8B/$16/>ASYNC_UART_LSR           {         MOV     DX,[>Async_Uart_LSR]       ;Yes -- pick up line status register}
  487.   /$EC                               {         IN      AL,DX                      ;and its contents}
  488.   /$24/$1E                           {         AND     AL,$1E                     ;Strip unwanted bits}
  489.   /$A2/>ASYNC_LINE_STATUS            {         MOV     [>Async_Line_Status],AL    ;Store for future reference}
  490.   /$08/$06/>ASYNC_LINE_ERROR_FLAGS   {         OR      [>Async_Line_Error_Flags],AL ;Add to any past transgressions}
  491.   /$E9/$97/$FE                       {         JMP     NEAR Poll}
  492.                                      {;}
  493.                                      {;  --- Modem status change ---}
  494.                                      {;}
  495.   /$3C/$00                           {Int0:    CMP     AL,0                       ;Check for modem status change}
  496.   /$74/$03                           {         JE      Int0a                      ;Yes -- handle it}
  497.   /$E9/$90/$FE                       {         JMP     NEAR Poll                  ;Else get next interrupt}
  498.                                      {;}
  499.   /$8B/$16/>ASYNC_UART_MSR           {Int0a:   MOV     DX,[>Async_Uart_MSR]       ;Pick up modem status reg. address}
  500.   /$EC                               {         IN      AL,DX                      ;and its contents}
  501.   /$A2/>ASYNC_MODEM_STATUS           {         MOV     [>Async_Modem_Status],AL   ;Store for future reference}
  502.   /$E8/$03/$00                       {         CALL    EnabWI                     ;Turn on write interrupts, in case}
  503.                                      {;                                           ;status change resulted from CTS/DSR}
  504.                                      {;                                           ;changing state.}
  505.   /$E9/$82/$FE                       {         JMP     NEAR Poll}
  506.                                      {;}
  507.                                      {;  Internal subroutine to enable write interrupts.}
  508.                                      {;}
  509.                                      {EnabWI: ;PROC    NEAR}
  510.   /$8B/$16/>ASYNC_UART_IER           {         MOV     DX,[>Async_Uart_IER]       ;Get interrupt enable register}
  511.   /$EC                               {         IN      AL,DX                      ;Check contents of IER}
  512.   /$A8/$02                           {         TEST    AL,2                       ;See if write interrupt enabled}
  513.   /$75/$03                           {         JNZ     EnabRet                    ;Skip if so}
  514.   /$0C/$02                           {         OR      AL,2                       ;Else enable write interrupts ...}
  515.   /$EE                               {         OUT     DX,AL                      ;... by rewriting IER contents}
  516.   /$C3                               {EnabRet: RET                                ;Return to caller}
  517.                                      {;}
  518.                                      {;  Send non-specific EOI to 8259 controller.}
  519.                                      {;}
  520.   /$B0/$20                           {Back:    MOV     AL,$20                     ;EOI = $20}
  521.   /$E6/$20                           {         OUT     $20,AL}
  522.                                      {;}
  523.                                      {;  Restore registers}
  524.                                      {;}
  525.   /$5F                               {         POP     DI}
  526.   /$07                               {         POP     ES}
  527.   /$5E                               {         POP     SI}
  528.   /$1F                               {         POP     DS}
  529.   /$5A                               {         POP     DX}
  530.   /$59                               {         POP     CX}
  531.   /$5B                               {         POP     BX}
  532.   /$58                               {         POP     AX}
  533.   /$89/$EC                           {         MOV     SP,BP}
  534.   /$5D                               {         POP     BP}
  535.   /$CF                               {         IRET}
  536. );
  537.  
  538. END    (* Async_Isr *);
  539.  
  540. (*----------------------------------------------------------------------*)
  541. (*               Async_Init --- Initialize Asynchronous Variables       *)
  542. (*----------------------------------------------------------------------*)
  543.  
  544. PROCEDURE Async_Init( Async_Buffer_Max  : INTEGER;
  545.                       Async_OBuffer_Max : INTEGER;
  546.                       Async_High_Lev1   : INTEGER;
  547.                       Async_High_Lev2   : INTEGER;
  548.                       Async_Low_Lev     : INTEGER );
  549.  
  550. (*----------------------------------------------------------------------*)
  551. (*                                                                      *)
  552. (*     Procedure:  Async_Init                                           *)
  553. (*                                                                      *)
  554. (*     Purpose:    Initializes variables                                *)
  555. (*                                                                      *)
  556. (*     Calling Sequence:                                                *)
  557. (*                                                                      *)
  558. (*         Async_Init( Async_Buffer_Max  : INTEGER;                     *)
  559. (*                     Async_OBuffer_Max : INTEGER;                     *)
  560. (*                     Async_High_Lev1   : INTEGER;                     *)
  561. (*                     Async_High_Lev2   : INTEGER;                     *)
  562. (*                     Async_Low_Lev     : INTEGER );                   *)
  563. (*                                                                      *)
  564. (*     Calls:  None                                                     *)
  565. (*                                                                      *)
  566. (*----------------------------------------------------------------------*)
  567.  
  568. (* STRUCTURED *) CONST
  569.  
  570.    Default_Com_Base : ARRAY[1..MaxComPorts] OF INTEGER =
  571.                       ( COM1_Base, COM2_Base, COM3_Base, COM4_Base );
  572.  
  573.    Default_Com_Irq  : ARRAY[1..MaxComPorts] OF INTEGER =
  574.                       ( COM1_Irq, COM2_Irq, COM3_Irq, COM4_Irq );
  575.  
  576.    Default_Com_RS232: ARRAY[1..MaxComPorts] OF INTEGER =
  577.                       ( COM1_RS232, COM2_RS232, COM3_RS232, COM4_RS232 );
  578.  
  579. VAR
  580.    I: INTEGER;
  581.  
  582. BEGIN   (* Async_Init *)
  583.                                    (* Save data segment address in code *)
  584.                                    (* segment for use in serial port    *)
  585.                                    (* interrupt handler.                *)
  586.    Async_DSeg_Save        := DSeg;
  587.  
  588.                                    (* No port open yet.                 *)
  589.    Async_Open_Flag        := FALSE;
  590.  
  591.                                    (* No XON/XOFF handling yet.         *)
  592.    Async_XOFF_Sent        := FALSE;
  593.    Async_XOFF_Received    := FALSE;
  594.    Async_XOFF_Rec_Display := FALSE;
  595.    Async_XON_Rec_Display  := FALSE;
  596.    Async_Send_XOFF        := FALSE;
  597.  
  598.                                    (* Set up empty receive buffer       *)
  599.    Async_Buffer_Overflow  := FALSE;
  600.    Async_Buffer_Used      := 0;
  601.    Async_MaxBufferUsed    := 0;
  602.    Async_Buffer_Head      := 0;
  603.    Async_Buffer_Tail      := 0;
  604.                                    (* Set up empty send buffer.         *)
  605.    Async_OBuffer_Overflow := FALSE;
  606.    Async_OBuffer_Used     := 0;
  607.    Async_MaxOBufferUsed   := 0;
  608.    Async_OBuffer_Head     := 0;
  609.    Async_OBuffer_Tail     := 0;
  610.                                    (* Set default wait time for output   *)
  611.                                    (* buffer to drain when it fills up.  *)
  612.    Async_Output_Delay     := 500;
  613.  
  614.                                    (* No modem or line errors yet.       *)
  615.    Async_Line_Status      := 0;
  616.    Async_Modem_Status     := 0;
  617.    Async_Line_Error_Flags := 0;
  618.  
  619.                                    (* Get buffer sizes *)
  620.  
  621.    IF ( Async_Buffer_Max > 0 ) THEN
  622.       Async_Buffer_Size := Async_Buffer_Max  - 1
  623.    ELSE
  624.       Async_Buffer_Size := 4095;
  625.  
  626.    IF ( Async_OBuffer_Max > 0 ) THEN
  627.       Async_OBuffer_Size := Async_OBuffer_Max - 1
  628.    ELSE
  629.       Async_OBuffer_Size := 1131;
  630.  
  631.                                    (* Get receive buffer overflow *)
  632.                                    (* check-points.               *)
  633.    IF ( Async_Low_Lev > 0 ) THEN
  634.       Async_Buffer_Low := Async_Low_Lev
  635.    ELSE
  636.       Async_Buffer_Low := Async_Buffer_Size DIV 4;
  637.  
  638.    IF ( Async_High_Lev1 > 0 ) THEN
  639.       Async_Buffer_High := Async_High_Lev1
  640.    ELSE
  641.       Async_Buffer_High := ( Async_Buffer_Size DIV 4 ) * 3;
  642.  
  643.    IF ( Async_High_Lev2 > 0 ) THEN
  644.       Async_Buffer_High_2 := Async_High_Lev2
  645.    ELSE
  646.       Async_Buffer_High_2 := ( Async_Buffer_Size DIV 10 ) * 9;
  647.  
  648.                                    (* Allocate buffers *)
  649.  
  650.    GETMEM( Async_Buffer_Ptr  , Async_Buffer_Size  + 1 );
  651.    GETMEM( Async_OBuffer_Ptr , Async_OBuffer_Size + 1 );
  652.  
  653.                                    (* No UART addresses defined yet *)
  654.    Async_Uart_IER         := 0;
  655.    Async_Uart_IIR         := 0;
  656.    Async_Uart_MSR         := 0;
  657.    Async_Uart_LSR         := 0;
  658.                                    (* Set default port addresses *)
  659.                                    (* and default IRQ lines      *)
  660.    FOR I := 1 TO MaxComPorts DO
  661.       BEGIN
  662.          Com_Base[I]  := Default_Com_Base [I];
  663.          Com_Irq [I]  := Default_Com_Irq  [I];
  664.          Com_RS232[I] := Default_Com_RS232[I];
  665.       END;
  666.  
  667. END     (* Async_Init *);
  668.  
  669. (*----------------------------------------------------------------------*)
  670. (*               Async_Close --- Close down communications interrupts   *)
  671. (*----------------------------------------------------------------------*)
  672.  
  673. PROCEDURE Async_Close( Drop_DTR: BOOLEAN );
  674.  
  675. (*----------------------------------------------------------------------*)
  676. (*                                                                      *)
  677. (*     Procedure:  Async_Close                                          *)
  678. (*                                                                      *)
  679. (*     Purpose:    Resets interrupt system when UART interrupts         *)
  680. (*                 are no longer needed.                                *)
  681. (*                                                                      *)
  682. (*     Calling Sequence:                                                *)
  683. (*                                                                      *)
  684. (*        Async_Close( Drop_DTR : BOOLEAN );                            *)
  685. (*                                                                      *)
  686. (*           Drop_DTR --- TRUE to drop DTR when closing down port       *)
  687. (*                                                                      *)
  688. (*     Calls:  None                                                     *)
  689. (*                                                                      *)
  690. (*----------------------------------------------------------------------*)
  691.  
  692. VAR
  693.    I : INTEGER;
  694.    M : INTEGER;
  695.  
  696. BEGIN  (* Async_Close *)
  697.  
  698.    IF Async_Open_Flag THEN
  699.       BEGIN
  700.  
  701.                      (* disable the IRQ on the 8259 *)
  702.  
  703.          INLINE($FA);                 (* disable interrupts *)
  704.  
  705.          I := Port[I8088_IMR];        (* get the interrupt mask register *)
  706.          M := 1 SHL Async_Irq;        (* set mask to turn off interrupt  *)
  707.          Port[I8088_IMR] := I OR M;
  708.  
  709.                      (* disable the 8250 interrupts *)
  710.  
  711.          Port[UART_IER + Async_Base] := 0;
  712.  
  713.                      (* Disable OUT2, RTS, OUT1 on the 8250, but *)
  714.                      (* possibly leave DTR enabled.              *)
  715.  
  716.          IF Drop_Dtr THEN
  717.             Port[UART_MCR + Async_Base] := 0
  718.          ELSE
  719.             Port[UART_MCR + Async_Base] := 1;
  720.  
  721.          INLINE($FB);                 (* enable interrupts *)
  722.  
  723.                      (* re-initialize our data areas so we know *)
  724.                      (* the port is closed                      *)
  725.  
  726.          Async_Open_Flag := FALSE;
  727.          Async_XOFF_Sent := FALSE;
  728.  
  729.                      (* Restore the previous interrupt pointers *)
  730.  
  731.          DOS_Set_Intrpt( Async_Irq + 8 , Async_Save_Iaddr[1],
  732.                                          Async_Save_Iaddr[2]  );
  733.  
  734.       END;
  735.  
  736. END    (* Async_Close *);
  737.  
  738. (*----------------------------------------------------------------------*)
  739. (*    Async_Clear_Errors --- Reset pending errors in async port         *)
  740. (*----------------------------------------------------------------------*)
  741.  
  742. PROCEDURE Async_Clear_Errors;
  743.  
  744. (*----------------------------------------------------------------------*)
  745. (*                                                                      *)
  746. (*     Procedure:   Async_Clear_Errors                                  *)
  747. (*                                                                      *)
  748. (*     Purpose:     Resets pending errors in async port                 *)
  749. (*                                                                      *)
  750. (*     Calling sequence:                                                *)
  751. (*                                                                      *)
  752. (*        Async_Clear_Errors;                                           *)
  753. (*                                                                      *)
  754. (*     Calls:  None                                                     *)
  755. (*                                                                      *)
  756. (*----------------------------------------------------------------------*)
  757.  
  758. VAR
  759.    I:  INTEGER;
  760.    M:  INTEGER;
  761.  
  762. BEGIN (* Async_Clear_Errors *)
  763.  
  764.                    (* Read the RBR and reset any pending error conditions. *)
  765.                    (* First turn off the Divisor Access Latch Bit to allow *)
  766.                    (* access to RBR, etc.                                  *)
  767.  
  768.    INLINE($FA);  (* disable interrupts *)
  769.  
  770.    Port[UART_LCR + Async_Base] := Port[UART_LCR + Async_Base] AND $7F;
  771.  
  772.                    (* Read the Line Status Register to reset any errors *)
  773.                    (* it indicates                                      *)
  774.  
  775.    I := Port[UART_LSR + Async_Base];
  776.  
  777.                    (* Read the Receiver Buffer Register in case it *)
  778.                    (* contains a character                         *)
  779.  
  780.    I := Port[UART_RBR + Async_Base];
  781.  
  782.                    (* enable the irq on the 8259 controller *)
  783.  
  784.    I := Port[I8088_IMR];  (* get the interrupt mask register *)
  785.    M := (1 SHL Async_Irq) XOR $00FF;
  786.  
  787.    Port[I8088_IMR] := I AND M;
  788.  
  789.                    (* enable OUT2 on 8250 *)
  790.  
  791.    I := Port[UART_MCR + Async_Base];
  792.    Port[UART_MCR + Async_Base] := I OR $0B;
  793.  
  794.                    (* enable the data ready interrupt on the 8250 *)
  795.  
  796.    Port[UART_IER + Async_Base] := $0F;
  797.  
  798.                    (* Re-enable 8259 *)
  799.  
  800.    Port[$20] := $20;
  801.  
  802.    INLINE($FB); (* enable interrupts *)
  803.  
  804. END   (* Async_Clear_Errors *);
  805.  
  806. (*----------------------------------------------------------------------*)
  807. (*    Async_Reset_Port --- Set/reset communications port parameters     *)
  808. (*----------------------------------------------------------------------*)
  809.  
  810. PROCEDURE Async_Reset_Port( ComPort       : INTEGER;
  811.                             BaudRate      : INTEGER;
  812.                             Parity        : CHAR;
  813.                             WordSize      : INTEGER;
  814.                             StopBits      : INTEGER  );
  815.  
  816. (*----------------------------------------------------------------------*)
  817. (*                                                                      *)
  818. (*     Procedure:   Async_Reset_Port                                    *)
  819. (*                                                                      *)
  820. (*     Purpose:     Resets communications port                          *)
  821. (*                                                                      *)
  822. (*     Calling Sequence:                                                *)
  823. (*                                                                      *)
  824. (*        Async_Reset_Port(   ComPort       : INTEGER;                  *)
  825. (*                            BaudRate      : INTEGER;                  *)
  826. (*                            Parity        : CHAR;                     *)
  827. (*                            WordSize      : INTEGER;                  *)
  828. (*                            StopBits      : INTEGER);                 *)
  829. (*                                                                      *)
  830. (*           ComPort  --- which port (1, 2, 3)                          *)
  831. (*           BaudRate --- Baud rate (110 to 19200)                      *)
  832. (*           Parity   --- "E" for even, "O" for odd, "N" for none       *)
  833. (*           WordSize --- Bits per character  (5 through 8)             *)
  834. (*           StopBits --- How many stop bits  (1 or 2)                  *)
  835. (*                                                                      *)
  836. (*     Calls:                                                           *)
  837. (*                                                                      *)
  838. (*        Async_Clear_Errors --- Clear async line errors                *)
  839. (*                                                                      *)
  840. (*----------------------------------------------------------------------*)
  841.  
  842. CONST   (* Baud Rate Constants *)
  843.  
  844.    Async_Num_Bauds = 9;
  845.  
  846.    Async_Baud_Table : ARRAY [1..Async_Num_Bauds] OF RECORD
  847.                                                        Baud, Bits : INTEGER;
  848.                                                     END
  849.  
  850.                     = ( ( Baud:  110;  Bits: $00 ),
  851.                         ( Baud:  150;  Bits: $20 ),
  852.                         ( Baud:  300;  Bits: $40 ),
  853.                         ( Baud:  600;  Bits: $60 ),
  854.                         ( Baud:  1200; Bits: $80 ),
  855.                         ( Baud:  2400; Bits: $A0 ),
  856.                         ( Baud:  4800; Bits: $C0 ),
  857.                         ( Baud:  9600; Bits: $E0 ),
  858.                         ( Baud: 19200; Bits: $E0 ) );
  859.  
  860. VAR
  861.    I       : INTEGER;
  862.    M       : INTEGER;
  863.    ComParm : INTEGER;
  864.  
  865. BEGIN (* Async_Reset_Port *)
  866.  
  867.             (*---------------------------------------------------*)
  868.             (*    Build the ComParm for RS232_Init               *)
  869.             (*    See Technical Reference Manual for description *)
  870.             (*---------------------------------------------------*)
  871.  
  872.                                    (* Set up the bits for the baud rate *)
  873.  
  874.    IF ( BaudRate > Async_Baud_Table[Async_Num_Bauds].Baud ) THEN
  875.       BaudRate := Async_Baud_Table[Async_Num_Bauds].Baud
  876.  
  877.    ELSE IF ( BaudRate < Async_Baud_Table[1].Baud ) THEN
  878.       BaudRate := Async_Baud_Table[1].Baud;
  879.  
  880.                                    (* Remember baud rate for purges *)
  881.    Async_Baud_Rate := BaudRate;
  882.  
  883.    I := 0;
  884.  
  885.    REPEAT
  886.       I := I + 1
  887.    UNTIL ( ( I >= Async_Num_Bauds ) OR
  888.            ( BaudRate = Async_Baud_Table[I].Baud ) );
  889.  
  890.    ComParm := Async_Baud_Table[I].Bits;
  891.  
  892.                                    (* Choose Parity *)
  893.    CASE UpCase(Parity) OF
  894.       'E' : ComParm := ComParm OR $0018;
  895.       'O' : ComParm := ComParm OR $0008;
  896.       'M' : ComParm := ComParm OR $0020;
  897.       'S' : ComParm := ComParm OR $0038;
  898.       ELSE ;
  899.    END (* CASE *);
  900.                                    (* Choose number of data bits *)
  901.  
  902.    WordSize := WordSize - 5;
  903.  
  904.    IF ( WordSize < 0 ) OR ( WordSize > 3 ) THEN
  905.       WordSize := 3;
  906.  
  907.    ComParm := ComParm OR WordSize;
  908.  
  909.                                    (* Choose stop bits *)
  910.  
  911.    IF StopBits = 2 THEN
  912.       ComParm := ComParm OR $0004;  (* default is 1 stop bit *)
  913.  
  914.                                    (* Use the BIOS COM port init routine *)
  915.  
  916.    BIOS_RS232_Init( ComPort - 1 , ComParm );
  917.  
  918.                                    (* If > 9600 baud, we have to screw *)
  919.                                    (* around a bit                     *)
  920.  
  921.    IF ( BaudRate = 19200 ) THEN
  922.       BEGIN
  923.  
  924.          I := PORT[ UART_LCR + Async_Base ];
  925.          PORT[ UART_LCR + Async_Base ] := I OR $80;
  926.  
  927.          PORT[ UART_THR + Async_Base ] := 6;
  928.          PORT[ UART_IER + Async_Base ] := 0;
  929.  
  930.          I := PORT[ UART_LCR + Async_Base ];
  931.          PORT[ UART_LCR + Async_Base ] := I AND $7F;
  932.  
  933.       END;
  934.                                    (* Clear any pending errors on *)
  935.                                    (* async line                  *)
  936.    Async_Clear_Errors;
  937.  
  938. END   (* Async_Reset_Port *);
  939.  
  940. (*----------------------------------------------------------------------*)
  941. (*               Async_Open --- Open communications port                *)
  942. (*----------------------------------------------------------------------*)
  943.  
  944. FUNCTION Async_Open( ComPort       : INTEGER;
  945.                      BaudRate      : INTEGER;
  946.                      Parity        : CHAR;
  947.                      WordSize      : INTEGER;
  948.                      StopBits      : INTEGER  ) : BOOLEAN;
  949.  
  950. (*----------------------------------------------------------------------*)
  951. (*                                                                      *)
  952. (*     Function:   Async_Open                                           *)
  953. (*                                                                      *)
  954. (*     Purpose:    Opens communications port                            *)
  955. (*                                                                      *)
  956. (*     Calling Sequence:                                                *)
  957. (*                                                                      *)
  958. (*        Flag := Async_Open( ComPort       : INTEGER;                  *)
  959. (*                            BaudRate      : INTEGER;                  *)
  960. (*                            Parity        : CHAR;                     *)
  961. (*                            WordSize      : INTEGER;                  *)
  962. (*                            StopBits      : INTEGER) : BOOLEAN;       *)
  963. (*                                                                      *)
  964. (*           ComPort  --- which port (1 though 3)                       *)
  965. (*           BaudRate --- Baud rate (110 to 19200)                      *)
  966. (*           Parity   --- "E" for even, "O" for odd, "N" for none,      *)
  967. (*                        "S" for space, "M" for mark.                  *)
  968. (*           WordSize --- Bits per character  (5 through 8)             *)
  969. (*           StopBits --- How many stop bits  (1 or 2)                  *)
  970. (*                                                                      *)
  971. (*           Flag returned TRUE if port initialized successfully;       *)
  972. (*           Flag returned FALSE if any errors.                         *)
  973. (*                                                                      *)
  974. (*     Calls:                                                           *)
  975. (*                                                                      *)
  976. (*        Async_Reset_Port --- initialize RS232 port                    *)
  977. (*        DOS_Set_Intrpt   --- set address of RS232 interrupt routine   *)
  978. (*                                                                      *)
  979. (*----------------------------------------------------------------------*)
  980.  
  981. BEGIN  (* Async_Open *)
  982.                              (* If port open, close it down first.  *)
  983.    IF Async_Open_Flag THEN
  984.       Async_Close( FALSE );
  985.                              (* Choose communications port *)
  986.  
  987.    IF ( ComPort < 1 ) THEN
  988.       ComPort := 1
  989.    ELSE IF ( ComPort > MaxComPorts ) THEN
  990.       ComPort := MaxComPorts;
  991.  
  992.    Async_Port  := ComPort;
  993.    Async_Base  := Com_Base [ ComPort ];
  994.    Async_Irq   := Com_Irq  [ ComPort ];
  995.    Async_RS232 := Com_RS232[ ComPort ];
  996.  
  997.                                    (* Set register pointers for ISR routine *)
  998.  
  999.    Async_Uart_IER  := Async_Base + UART_IER;
  1000.    Async_Uart_IIR  := Async_Base + UART_IIR;
  1001.    Async_Uart_MSR  := Async_Base + UART_MSR;
  1002.    Async_Uart_LSR  := Async_Base + UART_LSR;
  1003.  
  1004.                                    (* Check if given port installed *)
  1005.  
  1006.    IF (Port[UART_IIR + Async_Base] and $00F8) <> 0 THEN
  1007.       Async_Open := FALSE          (* Serial port not installed *)
  1008.    ELSE
  1009.       BEGIN   (* Open the port *)
  1010.  
  1011.                                    (* Get current interrupt address *)
  1012.  
  1013.          DOS_Get_Intrpt( Async_Irq + 8 , Async_Save_Iaddr[1],
  1014.                                          Async_Save_Iaddr[2]  );
  1015.  
  1016.                                    (* Set interrupt routine address *)
  1017.  
  1018.          DOS_Set_Intrpt( Async_Irq + 8 , CSeg , Ofs( Async_Isr ) );
  1019.  
  1020.                                    (* Set up UART                   *)
  1021.  
  1022.          Async_Reset_Port( ComPort, BaudRate, Parity, WordSize, StopBits );
  1023.  
  1024.          Async_Open      := TRUE;
  1025.          Async_Open_Flag := TRUE;
  1026.  
  1027.     END;
  1028.  
  1029. END   (* Async_Open *);
  1030.  
  1031.